import { useImperativeHandle, forwardRef,useRef,useState,useEffect } from "react"
import { useInput } from "@/hooks/useInput";
import {acceptList,showFileImageList} from  "@/utils/data"
import { throttle,isEmpty } from "lodash";
import PinyinEngine from "pinyin-engine";
import type {Tprops,AtEachMember} from "./types"
import "./style/chat-input-react.css"
import AtPopover from '../at-popover/index.tsx';


export interface ChildComponentMethods {
    insertFile: (file:File) => void;
    exportData:()=>void
}
const  ChatInputReact:any= forwardRef<ChildComponentMethods>((props:Tprops, ref)=>{
    const {cusStyle,atUserList:atUserPropsList,error:errorEmit,placeholder='请输入内容'}=props;
    const {insertImage,insertFile:insertFiles,insertContent,exportMsgData} =useInput({
        editorKey: "chat-input-next-editor",
    })

    // 插入文件
    const insertFile=(file:File)=>{
        const URL = window.URL || window.webkitURL;
        const url = URL.createObjectURL(file);
        if(file.type.includes("image")){
            insertImage(url,file)
        }
        else{
            const fileSuffix = file.name.substring(file.name.lastIndexOf("."));
            if (acceptList[1].includes(fileSuffix.toLowerCase())) {
                const fileType = [
                [".doc", ".docx"],
                [".xlsx", ".xls", ".csv"],
                [".zip", ".rar", ".7z"],
                [".txt", ".md"],
                [".pdf"],
                ];
                const index = fileType.findIndex((item) =>
                item.includes(fileSuffix.toLowerCase())
                );
                if (~index) {
                const img = showFileImageList[index];
                insertFiles(img,file)
                } else {
                    errorEmit&&errorEmit("暂不支持该文件类型进行该操作")
                }
            }
            // 视频文件
            if (acceptList[2].includes(fileSuffix.toLowerCase())) {
                const img = showFileImageList[5];
                insertFiles(img,file,true)
            }
        }
    }

    // 处理粘贴
    const handleParse = async (e: any) => {
        e.preventDefault();
        try{
        const result = (await onPaste(e)) as string;
        if (result) {
            document.execCommand("insertText", false, result);
        }
        }catch(err){
        errorEmit&&errorEmit(err as string)
        }
  };

    // 处理图片和文件在input框中的显示逻辑
    const handleFileAndImageInsert = (item: any) => {
        const file = item.getAsFile();
        const isLt8M = file.size / 1024 / 1024 < 8;
        if (!isLt8M) {
            errorEmit&&errorEmit('文件不能大于8M')
            return;
        }
        insertFile(file)
    };
  
    // 粘贴
    const onPaste = (e: any) => {
        if (!(e.clipboardData && e.clipboardData.items)) {
        return;
        }
        return new Promise((resolve, reject) => {
        for (let i = 0, len = e.clipboardData.items.length; i < len; i++) {
            const item = e.clipboardData.items[i];
            if (item.kind === "string") {
            item.getAsString((str: string) => {
                resolve(str);
            });
            } else if (item.kind === "file") {
            handleFileAndImageInsert(item);
            } else {
            reject(new Error("不允许复制这种类型!"));
            }
        }
        });
    };

    // 阻止默认事件
    const handleAllowDrop = (e: any) => {
        e.preventDefault();
    };
  
    // 放置
    const handleDrop = (e: any) => {
        e.preventDefault();
        const copyItems = e.dataTransfer.items;
        for (let i = 0; i < copyItems.length; i++) {
        // 字符串
        if (copyItems[i].kind === "string") {
            if (e.dataTransfer.effectAllowed === "copy") {
            copyItems[i].getAsString((str: string) => {
                insertContent(str);
            });
            }
        }
        // 文件
        if (copyItems[i].kind === "file") {
            handleFileAndImageInsert(copyItems[i]);
        }
        }
    };

    // 去除默认事件
    const handleKeyDown=(e:any)=>{
        const reason=e.keyCode===13&&!e.shiftKey||e.keyCode===40||e.keyCode===38
        if(reason){
            e.preventDefault()
        }
    }

    const chatInputNext=useRef<HTMLDivElement>(null)

    // 保持输入框滚动条在最下方
    const keepScrollBottom = throttle(
        () => {
        const scrollEle=chatInputNext.current
        if (scrollEle) {
            scrollEle.scrollTop = scrollEle?.scrollHeight;
        }
        },
        200,
        {
        leading: false,
        trailing: true,
        }
    );

    // @弹窗是否显示
    const [atPopoverVisible,setAtPopoverVisible]=useState(false)
    // @后跟的字符串
    const [atStr,setAtStr]=useState("")

    // 搜索出来的@列表
    const [searchAtList,setSeachAtList] = useState<Array<AtEachMember>>([]);

    // 搜索内容
    const searchFun=(searchStr:string)=>{
        const pinyinSearchList = new PinyinEngine(atUserPropsList, [
            "name",
        ]); 
        // 拼音搜索
        const newList = pinyinSearchList.query(searchStr);
        setSeachAtList(newList);
        if (searchStr && newList.length !== 0) {
            setAtPopoverVisible(true)
        } else if (newList.length === 0) {
            setAtPopoverVisible(false)
        }
    }

    // 处理input事件
    const handleInput=(e:any)=>{
        // 保持输入框滚动条在最底部
        keepScrollBottom();
        const inputE=e.nativeEvent
        const sel=window.getSelection() as Selection
        // 如果没有内容则隐藏@列表
        if (inputE.data !== null && !inputE.data.trim()) {
            setAtPopoverVisible(false);
        }
        else{
        const inputEle = e.target as any;
        let searchStr = "";
        let range = sel.getRangeAt(0); // 获取当前光标
        let isOnlyAt=false
        // 如果当前光标所在位置的节点类型是文本节点，且文本内容包含@符号，则获取@符号后面的文本就是搜索的内容
        for (let i = 0; i < inputEle.childNodes.length; i++) {
            const curEle = inputEle.childNodes[i];
            if (curEle.nodeName === "#text" && curEle.nodeValue.includes("@")) {
            const splitArr = curEle.nodeValue
                .substring(0, range.endOffset)
                .split("@");
            searchStr = splitArr[splitArr.length - 1];
            if (!searchStr || !searchStr.length) {
                isOnlyAt = true;
            }
            }
        }
        setAtStr(searchStr);
        if (
            inputE.inputType === "insertText" ||
            inputE.inputType === "insertCompositionText"
        ){
            // 输入字符
            if (inputE.data === "@") {
                setAtPopoverVisible(true);
            }else{
                searchFun(searchStr)
            }
        }else if (inputE.inputType === "deleteContentBackward") {
            const previousNode = range.startContainer.childNodes[range.startOffset - 1];
            if(previousNode&&previousNode.nodeName==='A'){
            e.preventDefault();
            // 删除整个 <a> 节点
            previousNode.remove();
            }
            //删除字符
            else if (!searchStr&&!isOnlyAt) {
                setAtPopoverVisible(false);
            } else {
                searchFun(searchStr)
            }
        }
        }
    }

    // 点击popver外部隐藏
    const handlePopoverClick=(e:Event)=>{
        const target = e.target as HTMLElement;
        const isSelf = document.getElementById('at-popover')?.contains(target);
        if(!isSelf){
            setAtPopoverVisible(false)
        }
    }
    // 监听@列表显示时的点击事件
    useEffect(()=>{
        if(atPopoverVisible){
            document.addEventListener('click',handlePopoverClick)
        }
        else{
            document.removeEventListener('click',handlePopoverClick)
        }
    },[atPopoverVisible])


    // 处理@确定事件
    const handleAtConfirm=(name:string)=>{
        const newAtEle = document.createElement("a");
        newAtEle.setAttribute("contenteditable", "false");
        newAtEle.setAttribute("style", "user-select: all");
        newAtEle.setAttribute("nickName", name);
        newAtEle.innerText = `@${name} `;
        insertContent(newAtEle.outerHTML,atStr)
        setAtPopoverVisible(false)
    }

    // 导出数据
    const exportData=()=>{
        const retrunData=exportMsgData()
        if(retrunData){
        const {msgData,needUploadFile,atUserList}=retrunData
        return {
            msgData,
            needUploadFile,
            atUserList
        }
        }
        return;
    }

    // 使用 useImperativeHandle 将 childMethod 绑定到 ref 上
    useImperativeHandle(ref, () => ({
        insertFile,
        exportData
    }));

    return (
        <>
            <div className="chat-input-next-wrap">
                <div 
                    contentEditable 
                    placeholder={placeholder} 
                    className="chat-input-next" 
                    style={{...cusStyle}} 
                    id="chat-input-next-editor"
                    ref={chatInputNext} 
                    onPaste={handleParse}
                    onInput={handleInput}
                    onKeyDown={handleKeyDown}
                    onDragOver={handleAllowDrop}
                    onDrop={handleDrop}
                ></div>
                 {!isEmpty(atUserPropsList)&&<AtPopover
                    visible={atPopoverVisible}
                    confirm={handleAtConfirm}
                    list={atStr?searchAtList:atUserPropsList}
                ></AtPopover>}
            </div> 
        </>
    )
})

export default ChatInputReact